#include <Arduino.h>
#include <ESPAsyncWebServer.h> //引入相应库
#include <ESP8266WiFi.h>
#include <Servo.h>

enum LoaderControlType
{
    Normal = 0,
    Up,
    Down,
    Left,
    Right,
    Loader_Up,
    Loader_Down
};

// D2(GPIO4) → GND D3(GPIO0) → VCC D4(GPIO2) → Controller
int leftGND = 4, leftVCC = 0, leftControlPin = 2;
Servo leftServo; // 左轮舵机

// D0(GPIO16) → GND D5(GPIO14) → VCC D6(GPIO12) → Controller
int rightGND = 16, rightVCC = 14, rightControlPin = 0;
Servo rightServo; // 右轮舵机

// TX(GPIO1) → GND RX(GPIO3) → VCC D1(GPIO5) → Controller
int loaderGND = 1, loaderVCC = 3, loaderControlPin = 4;
Servo loaderServo; // 装载舵机

// 以下为网页文件
String indexhtml = String("") +
                   "<!DOCTYPE html> \n" +
                   "<html> \n" +
                   "<head> \n" +
                   "    <meta charset=\"UTF-8\"> \n" +
                   "    <title>WebSocket Test</title> \n" +
                   "    <script> \n" +
                   "        var ws; \n" +
                   "        window.onload = function () { \n" +
                   "            if (\"WebSocket\" in window) { \n" +
                   "                ws = new WebSocket(\"ws://\" + window.location.host + \"/\"); // 建立WebSocket连接 \n" +
                   "                ws.onopen = function () { // 连接建立成功时触发 \n" +
                   "                    document.getElementById(\"info\").innerHTML += \"WebSocket连接成功！\" + \"<br>\"; \n" +
                   "                    ws.send(\"connect ok!\"); // 向服务器发送数据 \n" +
                   "                }; \n" +
                   "                ws.onmessage = function (evt) { // 收到服务器数据时触发 \n" +
                   "                    document.getElementById(\"info\").innerHTML += evt.data + \"<br>\"; \n" +
                   "                }; \n" +
                   "                ws.onerror = function () { // 发生错误时触发 \n" +
                   "                    document.getElementById(\"info\").innerHTML += \"通讯发送错误！\" + \"<br>\"; \n" +
                   "                }; \n" +
                   "                ws.onclose = function () { // 连接关闭时触发 \n" +
                   "                    document.getElementById(\"info\").innerHTML += \"WebSocketTest连接已关闭！\" + \"<br>\"; \n" +
                   "                }; \n" +
                   "            } \n" +
                   "            else { \n" +
                   "                document.getElementById(\"info\").innerHTML = \"浏览器不支持 WebSocket！\"; \n" +
                   "            } \n" +
                   "        }; \n" +
                   "        function send() { \n" +
                   "            console.log(\'error\'); \n" +
                   "            ws.send(\"Up\"); // 向服务器发送数据 \n" +
                   "        } \n" +
                   "    </script> \n" +
                   "</head> \n" +
                   "<body> \n" +
                   "    <button οnclick=\"send()\">点击向服务器发送数据</button> \n" +
                   "    <div id=\"info\"></div> \n" +
                   "</body> \n" +
                   "</html> \n";

const char AP_NameChar[] = "WiFiLoader";
const char AP_PasswordChar[] = "12345678"; //设置AP模式下模块所发出的WIFI的密码

AsyncWebServer server(8266); // 声明WebServer对象
AsyncWebSocket ws("/");      // WebSocket对象，url为/

void loaderControl(LoaderControlType controlType, int angle)
{
    switch (controlType)
    {
    case Normal:
        leftServo.write(90);
        rightServo.write(90);
        Serial.println("\nNomal");
        break;
    case Up:
        leftServo.write(180);
        rightServo.write(0);
        Serial.println("\n Up");
        break;
    case Down:
        leftServo.write(0);
        rightServo.write(180);
        Serial.println("\n Down");
        break;
    case Left:
        leftServo.write(0);
        rightServo.write(0);
        Serial.println("\n Left");
        break;
    case Right:
        leftServo.write(180);
        rightServo.write(180);
        Serial.println("\n Right");
        break;
    case Loader_Up:
        loaderServo.write(90);
        Serial.println("\n Loader_Up");
        break;
    case Loader_Down:
        loaderServo.write(0);
        Serial.println("\n Loader_Down");
        break;
    }
}

// WebSocket事件回调函数
void onEventHandle(AsyncWebSocket *server, AsyncWebSocketClient *client, AwsEventType type, void *arg, uint8_t *data, size_t len)
{
    if (type == WS_EVT_CONNECT) // 有客户端建立连接
    {
        Serial.printf("ws[%s][%u] connect\n", server->url(), client->id());
        client->printf("Hello Client %u !", client->id()); // 向客户端发送数据
        client->ping();                                    // 向客户端发送ping
    }
    else if (type == WS_EVT_DISCONNECT) // 有客户端断开连接
    {
        Serial.printf("ws[%s][%u] disconnect: %u\n", server->url(), client->id());
    }
    else if (type == WS_EVT_ERROR) // 发生错误
    {
        Serial.printf("ws[%s][%u] error(%u): %s\n", server->url(), client->id(), *((uint16_t *)arg), (char *)data);
    }
    else if (type == WS_EVT_PONG) // 收到客户端对服务器发出的ping进行应答（pong消息）
    {
        Serial.printf("ws[%s][%u] pong[%u]: %s\n", server->url(), client->id(), len, (len) ? (char *)data : "");
    }
    else if (type == WS_EVT_DATA) // 收到来自客户端的数据
    {
        AwsFrameInfo *info = (AwsFrameInfo *)arg;
        Serial.printf("ws[%s][%u] frame[%u] %s[%llu - %llu]: ", server->url(), client->id(), info->num, (info->message_opcode == WS_TEXT) ? "text" : "binary", info->index, info->index + len);
        data[len] = 0;
        Serial.printf("%s\n", (char *)data);
        LoaderControlType loaderType = Normal;
        if (strcmp("Up", (char *)data) == 0)
        {
            loaderType = Up;
        }
        if (strcmp("Down", (char *)data) == 0)
        {
            loaderType = Down;
        }
        if (strcmp("Left", (char *)data) == 0)
        {
            loaderType = Left;
        }
        if (strcmp("Right", (char *)data) == 0)
        {
            loaderType = Right;
        }
        if (strcmp("Loader_Up", (char *)data) == 0)
        {
            loaderType = Loader_Up;
        }
        if (strcmp("Loader_Down", (char *)data) == 0)
        {
            loaderType = Loader_Down;
        }
        loaderControl(loaderType, 0);
    }
}

void initWebSocket()
{
    WiFi.mode(WIFI_AP);
    WiFi.softAP(AP_NameChar, AP_PasswordChar);

    Serial.print("\nIP: ");
    Serial.println(WiFi.softAPIP());

    ws.onEvent(onEventHandle); // 绑定回调函数
    server.addHandler(&ws);    // 将WebSocket添加到服务器中

    server.on("/", HTTP_GET, [](AsyncWebServerRequest *request) { //注册链接"/lambda"与对应回调函数（匿名函数形式声明）
        request->send(200, "text/html", indexhtml);               //向客户端发送响应和内容
    });
    server.begin(); //启动服务器

    Serial.println("Web server started");
}

void initServo()
{
    // pinMode(leftGND, OUTPUT);
    // digitalWrite(leftGND, LOW);
    // pinMode(leftVCC, OUTPUT);
    // digitalWrite(leftVCC, HIGH);

    // pinMode(rightGND, OUTPUT);
    // digitalWrite(rightGND, LOW);
    // pinMode(rightVCC, OUTPUT);
    // digitalWrite(rightVCC, HIGH);

    // pinMode(loaderGND, OUTPUT);
    // digitalWrite(loaderGND, LOW);
    // pinMode(loaderVCC, OUTPUT);
    // digitalWrite(loaderVCC, HIGH);

    leftServo.attach(leftControlPin);
    rightServo.attach(rightControlPin);
    loaderServo.attach(loaderControlPin);
}

void setup()
{
    Serial.begin(9600);
    Serial.println("\nBegin now!!!");
    initWebSocket();
    initServo();
}

void loop()
{
    delay(2000);
    ws.cleanupClients(); // 关闭过多的WebSocket连接以节省资源
}